import IEntitySystem from "../../base/ECSR/IEntitySystem";
import CollisionComponent from "../components/CollisionComponent";
import BubbleComponent from "../components/BubbleComponent";
import MapComponent from "../components/MapComponent";
import GameClientData from "../data/GameClientData";

export default class CollisionSystem extends IEntitySystem
{
    constructor(world)
    {
        super(world);
    }
    // 每逻辑帧调用
    Execute()
    {
        let collisionComList = this.world.GetComponents("CollisionComponent") as Array<CollisionComponent>;
        let mapCom = this.world.GetComponentByEntityId(GameClientData.mapId, "MapComponent") as MapComponent;

        for(let i = 0; i < collisionComList.length; ++i)
        {
            let collisionCom = collisionComList[i];
            let vec2 = collisionCom.rowAndCol;

            let activeNode = mapCom.bubbleMap[vec2.x][vec2.y];

            let joinNodes = this.TriggerNode(activeNode, mapCom.bubbleMap);
            cc.log("CollisionSystem|" + joinNodes.length);
            joinNodes.forEach(item=>{
                let bubble = this.world.GetComponentByEntityId(item, "BubbleComponent") as BubbleComponent;
                bubble.colorType = 3;
                cc.log(bubble.row + "," + bubble.col + "," + bubble.bfsLevel)
            });

            // let removeBubbleCom
        }
    }

    TriggerNode(activeNode:string, bubbleMap:string[][]): string[]
    {
        let joinNodes:string[] = [];
        let bfsQueue:string[] = [];

        joinNodes.push(activeNode);
        bfsQueue.push(activeNode);

        (this.world.GetComponentByEntityId(activeNode, "BubbleComponent") as BubbleComponent).isBfsVisit = true;

        /**
         * 按照广度优先遍历寻找符合要求的结点
         */
        for(let bfsLevel = 0; bfsQueue.length > 0; bfsLevel++)
        {
            // 存储下一层的结点
            let nextLevelNodes = [];
            // 寻找以本层结点为中心的结点
            while(bfsQueue.length > 0)
            {
                let item = bfsQueue.pop();
                let bubbleCom = this.world.GetComponentByEntityId(activeNode, "BubbleComponent") as BubbleComponent;
                bubbleCom.bfsLevel = bfsLevel;

                let nodes = this.BfsFindTypeNodes(item, bubbleMap);
                // 过滤掉已经访问过的
                nodes.filter(newNode=>{
                    let bubbleCom = this.world.GetComponentByEntityId(newNode, "BubbleComponent") as BubbleComponent;
                    return !bubbleCom.isBfsVisit;
                }).forEach(newNode=>{
                    let bubbleCom = this.world.GetComponentByEntityId(newNode, "BubbleComponent") as BubbleComponent;
                    bubbleCom.isBfsVisit = true;
                    nextLevelNodes.push(newNode);
                    joinNodes.push(newNode);
                });
            }

            bfsQueue = nextLevelNodes;
        }


        // 查找完毕，重置访问标识
        joinNodes.forEach(node=>{
            let bubbleCom = this.world.GetComponentByEntityId(node, "BubbleComponent") as BubbleComponent;
            bubbleCom.isBfsVisit = false;
        });
        
        return joinNodes;
    }

    BfsFindTypeNodes(originNode:string, bubbleMap:string[][]): string[]
    {
        let originBubble = this.world.GetComponentByEntityId(originNode, "BubbleComponent") as BubbleComponent;
        let nodes:string[] = [];
        let row = originBubble.row;
        let col = originBubble.col;
        let type = originBubble.colorType;

        if(row < 0 || row > bubbleMap.length || col < 0 || col > (row+1) % 2 + 10)
        {
            return nodes;
        }
        
        let offsetCol = row % 2 == 0 ? col  -1: col;

        if(row - 1 >= 0)
        {
            if(offsetCol < bubbleMap[row-1].length && bubbleMap[row-1][offsetCol] !== null)
            {
                let tmpNode = bubbleMap[row-1][offsetCol];
                let tmpCom = this.world.GetComponentByEntityId(tmpNode, "BubbleComponent") as BubbleComponent;
                if(tmpCom.colorType === type)
                {
                    nodes.push(tmpNode);
                }
            }
            if(offsetCol + 1 < bubbleMap[row-1].length && bubbleMap[row-1][offsetCol+1] !== null)
            {
                let tmpNode = bubbleMap[row-1][offsetCol+1];
                let tmpCom = this.world.GetComponentByEntityId(tmpNode, "BubbleComponent") as BubbleComponent;
                if(tmpCom.colorType == type)
                {
                    nodes.push(tmpNode);
                }
            }
        }

        if(row < bubbleMap.length)
        {
            if(col -1 >= 0 && bubbleMap[row][col-1] != null)
            {
                let tmpNode = bubbleMap[row][col-1];
                let tmpCom = this.world.GetComponentByEntityId(tmpNode, "BubbleComponent") as BubbleComponent;
                if(tmpCom.colorType == type)
                {
                    nodes.push(tmpNode);
                }
            }
            if(col + 1 < bubbleMap[row].length && bubbleMap[row][col+1] != null)
            {
                let tmpNode = bubbleMap[row][col+1];
                let tmpCom = this.world.GetComponentByEntityId(tmpNode, "BubbleComponent") as BubbleComponent;
                if(tmpCom.colorType == type)
                {
                    nodes.push(tmpNode);
                }
            }
        }

        if(row + 1 < bubbleMap.length)
        { 
            if(offsetCol < bubbleMap[row+1].length && bubbleMap[row+1][offsetCol] != null)
            {
                let tmpNode = bubbleMap[row+1][offsetCol];
                let tmpCom = this.world.GetComponentByEntityId(tmpNode, "BubbleComponent") as BubbleComponent;
                if(tmpCom.colorType == type)
                {
                    nodes.push(tmpNode);
                }
            }
            if(offsetCol + 1 < bubbleMap[row].length && bubbleMap[row+1][offsetCol+1] != null)
            {
                let tmpNode = bubbleMap[row+1][offsetCol+1];
                let tmpCom = this.world.GetComponentByEntityId(tmpNode, "BubbleComponent") as BubbleComponent;
                if(tmpCom.colorType == type)
                {
                    nodes.push(tmpNode);
                }
            }
        }

        return nodes;
    }

}